package com.yuqih.common;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.yuqih.common.json.DefaultObjectMapperConfiguration;
import com.yuqih.common.json.IObjectMapperConfiguration;

public class Global {

	private static final Logger logger = LoggerFactory.getLogger(Global.class);
	
	private static final String objectMapperConfigurationResource = "classpath:settings/jackson.conf";

	public static final ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

	public static final ObjectMapper objectMapper;

	static {
		ObjectMapper mapper;
		Resource resource = resourcePatternResolver.getResource(objectMapperConfigurationResource);
		if (!resource.exists()) {
			mapper = getDefaultObjectMapper();
		} else {
			try {
				mapper = new ObjectMapper();
				configure(resource, mapper);
				logger.info("初始化全局ObjectMapper成功，使用配置：{}" , objectMapperConfigurationResource);
			} catch (Exception e) {
				logger.warn("初始化全局ObjectMapper失败，使用配置：{}" , objectMapperConfigurationResource, e);
				mapper = getDefaultObjectMapper();
			}
		}

		objectMapper = mapper;
	}

	private static ObjectMapper getDefaultObjectMapper() {
		ObjectMapper mapper = new ObjectMapper();
		logger.info("初始化全局ObjectMapper，使用默认配置");
		DefaultObjectMapperConfiguration.instance.configure(mapper);
		return mapper;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private static void configure(Resource resource, ObjectMapper mapper) throws Exception {
		InputStream ins = null;
		try {
			ins = resource.getInputStream();
			List<String> names = IOUtils.readLines(ins, StandardCharsets.UTF_8);
			
			Map<Class<?>, JsonSerializer<?>> serializerMap = new LinkedHashMap<>();
			Map<Class<?>, JsonDeserializer<?>> deserializerMap = new LinkedHashMap<>();
			
			for (String name : names) {
				Class<?> type = Class.forName(name);
				if (IObjectMapperConfiguration.class.isAssignableFrom(type)) {
					IObjectMapperConfiguration configuration = (IObjectMapperConfiguration) type.newInstance();
					configuration.configure(mapper);
				} else if (JsonSerializer.class.isAssignableFrom(type)) {
					Class<?> genericType = GenericTypeResolver.resolveTypeArgument(type, JsonSerializer.class);
					if (genericType == null) {
						throw new IllegalArgumentException(type + "不是有效的类型");
					}
					serializerMap.put(genericType, (JsonSerializer<?>) type.newInstance());
				} else if (JsonDeserializer.class.isAssignableFrom(type)) {
					Class<?> genericType = GenericTypeResolver.resolveTypeArgument(type, JsonDeserializer.class);
					if (genericType == null) {
						throw new IllegalArgumentException(type + "不是有效的类型");
					}
					deserializerMap.put(genericType, (JsonDeserializer<?>) type.newInstance());
				} else {
					throw new IllegalArgumentException(type + "不是有效的类型");
				}
				
			}
			
			if (!serializerMap.isEmpty() || !deserializerMap.isEmpty()) {
				SimpleModule objectIdModule = new SimpleModule();
				
				for (Entry<Class<?>, JsonSerializer<?>> entry : serializerMap.entrySet()) {
					objectIdModule.addSerializer((Class)entry.getKey(), (JsonSerializer)entry.getValue());
				}
				
				for (Entry<Class<?>, JsonDeserializer<?>> entry : deserializerMap.entrySet()) {
					objectIdModule.addDeserializer((Class)entry.getKey(), (JsonDeserializer)entry.getValue());
				}
				
				mapper.registerModule(objectIdModule);
			}
		} finally {
			IOUtils.closeQuietly(ins);
		}
	}

}
